/*
 * Copyright 2010-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.pathlet.core;

import org.pathlet.core.config.ConfigException;
import org.pathlet.core.config.def.BeanResourceConfig;
import org.pathlet.core.config.impl.BeanResourceConfigHandler;
import org.pathlet.core.exception.ResourceInstanceException;
import org.pathlet.core.impl.BaseResource;
import org.pathlet.util.ValueUtils;

import java.lang.reflect.InvocationTargetException;

/**
 *
 * @author Charlie Zhang
 *
 */
public class BeanResource extends BaseResource {

	private BeanResourceConfig config;

	private boolean fromMethod;

	private BeanResourceConfigHandler configHandler = null;

	//private boolean destroyable;

	//用来存储配置信息，如ContextIn, TargetIn, ResourceIn, DestroyMethod, initMehtod 等, 这些信息可以来自配置文件，也可以是Annotation。
    //这样储存主要用于统一配置的程序处理入口，同时也减少多次重复分析的消耗，加速多次处理的速度。
    //属性的设置..., 所有配置的
    //AOP部分的加载和初始化
	//private BeanResourceConfigHandler configHandler;

	public BeanResource(ResourceFactory creator, BeanResourceConfig config) throws ResourceInstanceException {
		super(creator);
		this.config = config;
		this.fromMethod = (ValueUtils.notEmpty(config.getFromMethod())) ? true : false;
	}

	public BeanResourceConfigHandler getConfigHandler() {
		if(configHandler == null) {
			configHandler = new BeanResourceConfigHandler(getFactory().getContainer(), config);
		}
		return configHandler;
	}

	public String getScope() {
		return config.getScope();
	}

	public Path getPath() {
		return config.getPath();
	}

	public Class getTargetType() {
		 return getConfigHandler().getBeanClass();
	}

	public BeanResourceConfig getConfig() {
		return config;
	}

	public boolean destroyable() {
		return (config.getDestroyMethod() != null);
	}

	public void destroyInstance(InstanceSpace context, Object target) {
		BeanResourceConfigHandler configHandler = getConfigHandler();
		if(configHandler.getDestroyMethod() != null) {
			try {
				configHandler.getDestroyMethod().invoke(target);
			}
			catch (Exception e) {
				String message = "Failed execution the destroyMethod " + configHandler.getDestroyMethod() + "() in the class '" + target.getClass().getName() + "'";
				if(e.getCause() == null) {
					throw new ConfigException(message, e);
				}
				else {
					throw new ConfigException(message, e.getCause());
				}
			}
		}
	}

	protected Object doInstanceTarget(InstanceSpace context)  {
		try {
			BeanResourceConfigHandler handler = getConfigHandler();
			if(fromMethod) {
				return handler.getBeanCreatorMethod().invoke(handler.getBeanCreatorInstance());
			}
			else {
				return handler.getBeanClass().newInstance();
			}
		}
		catch (InstantiationException | IllegalAccessException | InvocationTargetException ie)
		{
			throw new ResourceInstanceException(ie, this);
		}
	}

	protected void afterInstanceTarget(InstanceSpace context, Object target) {
		BeanResourceConfigHandler configHandler = getConfigHandler();
		if(configHandler.getInitMethod() != null) {
			try {
				configHandler.getInitMethod().invoke(target);
			}
			catch (Exception e) {
				String message = "Failed execution the initMethod " + configHandler.getInitMethod() + "() in the class '" + target.getClass().getName() + "'";
				if(e.getCause() == null) {
					throw new ConfigException(message, e);
				}
				else {
					throw new ConfigException(message, e.getCause());
				}
			}
		}
	}


}
